package com.yungu.swift.lbs.trace.google;

import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.StringUtils;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 谷歌地图Directions接口工具类
 *
 * @author Zerrion
 * @date 2018/1/19
 */
public class GoogleDirectionsUtils {
    private static final Logger logger = LoggerFactory.getLogger(GoogleDirectionsUtils.class);
    private static final String GOOGLE_MAPS_DIRECTIONS_URL = "https://maps.googleapis.com/maps/api/directions/json?units=metric";
    private static final String ZTE_GOOGLE_MAPS_DIRECTIONS_API_KEY = "AIzaSyBOhF2HHZllZWn06ra9lvh0MVwVkxyupqI";
    private static final int DISTANCE_UNIT_TYPE_KILOMETRE = 1;
    private static final int DISTANCE_UNIT_TYPE_METRE = 2;

    /**
     * 通过地图计算路径里程
     *
     * @param originPointCount 源点个数
     * @param resultPointCount 取点个数
     * @return int[]
     * @author Zerrion
     * @date 2018/2/28
     */
    public static int[] getWayPointIndexArray(int originPointCount, int resultPointCount) {
        int[] pointIndexArray;
        //若小于取点个数，则直接截取
        if (originPointCount < resultPointCount) {
            pointIndexArray = new int[originPointCount];
            for (int arrayIndex = 0; arrayIndex < originPointCount; arrayIndex++) {
                pointIndexArray[arrayIndex] = arrayIndex;
            }
        }
        //若大于取点个数，则计算步长
        else {
            pointIndexArray = new int[resultPointCount];
            int step = (int) Math.floor(originPointCount / resultPointCount);
            for (int arrayIndex = 0, pointIndex = 0; arrayIndex < resultPointCount; arrayIndex++, pointIndex += step) {
                pointIndexArray[arrayIndex] = pointIndex;
            }
        }
        return pointIndexArray;
    }

    /**
     * 通过地图计算路径里程
     *
     * @param origin      起点经纬度（lat,lng）
     * @param destination 终点经纬度（lat,lng）
     * @param waypoints   中途路径点（lat,lng|lat,lng...）
     * @return BigDecimal
     * @author Zerrion
     * @date 2018/2/27
     */
    public static BigDecimal getMinute(String origin, String destination, String waypoints) {
        String result = invokeGoogleAPI(origin, destination, waypoints);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        try {
            Map map = JsonUtils.readValue(result, Map.class);
            if ("OK".equals(map.get("status"))) {
                List routes = (List) map.get("routes");
                if (routes.size() > 0) {
                    Integer duration = (Integer) ((Map) ((Map) ((List) ((Map) routes.get(0)).get("legs")).get(0)).get("duration")).get("value");
                    return new BigDecimal(duration).divide(new BigDecimal(60), 0, BigDecimal.ROUND_DOWN).add(BigDecimal.ONE);
                } else {
                    logger.error("Google API Directions - getMinute - ZERO_RESULTS");
                    return null;
                }
            } else {
                logger.error("Google API Directions - getMinute - 参数错误");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 计算距离（单位：米）
     *
     * @param origin      起点经纬度（lat,lng）
     * @param destination 终点经纬度（lat,lng）
     * @param waypoints   中途路径点（lat,lng|lat,lng...）
     * @return BigDecimal
     * @author Zerrion
     * @date 2018/2/27
     */
    public static BigDecimal getMetre(String origin, String destination, String waypoints) {
        return getDistance(origin, destination, waypoints, DISTANCE_UNIT_TYPE_METRE);
    }

    /**
     * 计算距离（单位：公里）
     *
     * @param origin      起点经纬度（lat,lng）
     * @param destination 终点经纬度（lat,lng）
     * @param waypoints   中途路径点（lat,lng|lat,lng...）
     * @return BigDecimal
     * @author Zerrion
     * @date 2018/2/27
     */
    public static BigDecimal getKilometre(String origin, String destination, String waypoints) {
        return getDistance(origin, destination, waypoints, DISTANCE_UNIT_TYPE_KILOMETRE);
    }

    /**
     * 通过地图计算路径里程
     *
     * @param origin      起点经纬度（lat,lng）
     * @param destination 终点经纬度（lat,lng）
     * @param waypoints   中途路径点（lat,lng|lat,lng...）
     * @param unitType    公里类型:1, 米类型:2
     * @return BigDecimal
     * @author Zerrion
     * @date 2018/2/27
     */
    public static BigDecimal getDistance(String origin, String destination, String waypoints, Integer unitType) {
        String result = invokeGoogleAPI(origin, destination, waypoints);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        try {
            Map map = JsonUtils.readValue(result, Map.class);
            if ("OK".equals(map.get("status"))) {
                List routes = (List) map.get("routes");
                if (routes.size() > 0) {
                    Integer distance = (Integer) ((Map) ((Map) ((List) ((Map) routes.get(0)).get("legs")).get(0)).get("distance")).get("value");
                    if (DISTANCE_UNIT_TYPE_KILOMETRE == unitType) {
                        return new BigDecimal(distance).divide(new BigDecimal(1000), 1, BigDecimal.ROUND_HALF_UP);
                    } else {
                        return new BigDecimal(distance);
                    }
                } else {
                    logger.error("Google API Directions - getKilometre - ZERO_RESULTS");
                    return null;
                }
            } else {
                logger.error("Google API Directions - getKilometre - 参数错误");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过地图计算路径里程
     *
     * @param origin      起点经纬度（lat,lng）
     * @param destination 终点经纬度（lat,lng）
     * @param waypoints   中途路径点（lat,lng|lat,lng...）
     * @return BigDecimal
     * @author Zerrion
     * @date 2018/2/27
     */
    public static Map<String, Object> getKilometreAndMinute(String origin, String destination, String waypoints) {
        String result = invokeGoogleAPI(origin, destination, waypoints);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        try {
            Map map = JsonUtils.readValue(result, Map.class);
            if ("OK".equals(map.get("status"))) {
                List routes = (List) map.get("routes");
                if (routes.size() > 0) {
                    Integer distance = (Integer) ((Map) ((Map) ((List) ((Map) routes.get(0)).get("legs")).get(0)).get("distance")).get("value");
                    BigDecimal measureDistance = new BigDecimal(distance).divide(new BigDecimal(1000), 1, BigDecimal.ROUND_HALF_UP);
                    Integer duration = (Integer) ((Map) ((Map) ((List) ((Map) routes.get(0)).get("legs")).get(0)).get("duration")).get("value");
                    BigDecimal measureDuration = new BigDecimal(duration).divide(new BigDecimal(60), 0, BigDecimal.ROUND_DOWN).add(BigDecimal.ONE);
                    return MapUtils.build(new String[]{"distance", "duration"}, new Object[]{measureDistance, measureDuration});
                } else {
                    logger.error("Google API Directions - getKilometreAndMinute - ZERO_RESULTS");
                    return null;
                }
            } else {
                logger.error("Google API Directions - getKilometreAndMinute - 参数错误");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 调用谷歌API方法
     *
     * @param origin      起点
     * @param destination 终点
     * @return String
     * @author Zerrion
     * @date 2018/1/9
     */
    private static String invokeGoogleAPI(String origin, String destination, String waypoints) {
        String url = GOOGLE_MAPS_DIRECTIONS_URL + "&origin=" + origin + "&destination=" + destination;
        if (StringUtils.isNotEmpty(waypoints)) {
            url += "&waypoints=" + GooglePolylineUtils.encode(waypoints);
        }
        Map<String, Object> resultMap = GoogleRequestUtils.get(url, ZTE_GOOGLE_MAPS_DIRECTIONS_API_KEY);
        Integer status = (Integer) resultMap.get("status");
        String result = (String) resultMap.get("result");
        if (HttpStatus.SC_OK == status) {
            return result;
        } else {
            logger.error("请求谷歌Directions接口-超时");
            return null;
        }
    }

}
